#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <FS.h> //文件系统头文件

//制作文件系统：
//1. 在工程目录下创建名为data的目录，此目录中的文件会放到文件系统中
//2. 点击工具菜单中的“ESP8266 Sketch Data Upload” 制作文件系统镜像并烧写到flash中
//注意：烧写文件系统时，不要打开串口监视器

ESP8266WebServer server;

//根目录请求的处理函数
void handleRoot(void)
{
  //响应报文发送函数
  //参数1：状态码
  //参数2：返回资源的类型（响应头中Content-Type字段的值）
  //参数3：响应报文的正文
  //server.send(200, "text/html", "<html><body><p>Hello World!</p></body></html>");
  File file = SPIFFS.open("/index.html", "r");//只读方式打开文件
  server.streamFile(file, "text/html;charset=utf-8"); //发送文件到客户端
  file.close(); //关闭文件
  
  String cmd = server.arg("switch");//获取参数内容
  if (cmd == "on")
  {
    //开灯
    digitalWrite(LED_BUILTIN, LOW);
  }

  if (cmd == "off")
  {
    //关灯
    digitalWrite(LED_BUILTIN, HIGH);
  }
}

String temp;//从传感器读取温湿度
String humi;

//计算高电平/低电平的持续时间，并等待
int waitLevel(int pin, int level)
{
  int count = 0;
  while (digitalRead(pin) == level)
  {
    count++;
    if (count > 1000) break; //等待时间超过1ms，强制结束等待
    delayMicroseconds(1);
  }

  return count;
}

void dht_read(int pin)
{
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW); //主机发送起始信号
  delay(19); //低电平维持18ms以上
  //将数据线上的电平拉高，并等待DHT11响应
  pinMode(pin, INPUT_PULLUP);
  delayMicroseconds(40); //等待DHT11将数据线电平拉低

  waitLevel(pin, LOW); //等待低电平结束
  waitLevel(pin, HIGH); //等待高电平结束

  char data[5]; //保存接收的数据40bit
  for (int i = 0; i < 40; i++) //循环接收40个bit的数据
  {
    data[i/8] = data[i/8] << 1; //已接收的数据左移1位，准备接收下一个bit
    int low_time = waitLevel(pin, LOW); //低电平持续时间
    int high_time = waitLevel(pin, HIGH); //高电平持续时间
    if (low_time < high_time)
    {
      data[i/8] |= 1;//将最右边的bit位置1
      //位或
      // 10101010
      // 00000001
      //----------or
      // 10101011
    }
    else
    {
      data[i/8] &= 0xFE; //将最右边的bit位设置为0
      //位与
      // 01010101
      // 11111110 <- 0xFE
      //----------and
      // 01010100
    }
  }

  char chksum = data[0] + data[1] + data[2] + data[3];//计算校验和
  if (chksum != data[4]) //校验和出错，不保存数据
  {
    return;
  }

  humi = String((int)data[0]) + "." + String((int)data[1]);
  temp = String((int)data[2]) + "." + String((int)data[3]);
}

void handleSensor(void)
{
  dht_read(D1);
  //拼接JSON字符串
  String json = "{\"temp\":" + temp + ",\"humi\":" + humi + "}";
  server.send(200, "application/json", json); //将JSON字符串发给客户端
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(74880);
  WiFi.mode(WIFI_STA);
  WiFi.begin("LIUYU", "12345678");
  while (!WiFi.isConnected())
  {
    delay(100);
  }
  Serial.println("网络连接成功，IP：" + WiFi.localIP().toString());

  SPIFFS.begin(); //初始化文件系统
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH); //默认关闭LED

  server.on("/", handleRoot);//处理根目录请求
  server.on("/sensor", handleSensor);//获取温湿度
  server.serveStatic("/favicon.ico", SPIFFS, "/favicon.ico"); //访问静态文件（文件系统中的文件），不需要自己写处理函数
  server.begin(); //启动网页服务器
  Serial.println("网页服务已启动");
}

void loop() {
  // put your main code here, to run repeatedly:
  server.handleClient(); //处理客户端请求
}
